package design.simdi.code.final_paper.site.panels;

import java.util.Arrays;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.wicket.Component;
import org.apache.wicket.Page;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior;
import org.apache.wicket.extensions.wizard.WizardModel;
import org.apache.wicket.extensions.wizard.WizardStep;
import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.markup.html.form.PasswordTextField;
import org.apache.wicket.markup.html.form.TextArea;
import org.apache.wicket.markup.html.form.TextField;
import org.apache.wicket.model.CompoundPropertyModel;
import org.apache.wicket.model.Model;
import org.apache.wicket.model.PropertyModel;
import org.apache.wicket.model.ResourceModel;
import org.apache.wicket.model.StringResourceModel;
import org.apache.wicket.spring.injection.annot.SpringBean;
import org.apache.wicket.util.value.ValueMap;
import org.apache.wicket.validation.IValidatable;
import org.apache.wicket.validation.validator.AbstractValidator;
import org.apache.wicket.validation.validator.EmailAddressValidator;

import design.simdi.code.final_paper.core.entities.Absolvent;
import design.simdi.code.final_paper.core.entities.Person;
import design.simdi.code.final_paper.core.entities.Profesor;
import design.simdi.code.final_paper.core.entities.Student;
import design.simdi.code.final_paper.core.entities.User;
import design.simdi.code.final_paper.core.enums.TipContEnum;
import design.simdi.code.final_paper.core.services.ServiceException;
import design.simdi.code.final_paper.core.services.UserService;
import design.simdi.code.final_paper.site.pages.BasePage;
import design.simdi.code.final_paper.utils.TipContComboBox;

/**
 * 
 * @author Marius Dumitriu - (Jun 3, 2010 - 10:44:09 PM)
 * 
 */
public class NewUserWizardPanels extends MyWizard {

	private static final long serialVersionUID = 1L;

	private Person person;
	private Component backComponent;

	@SpringBean
	private UserService userService;
	// user
	private PasswordTextField password;
	private PasswordTextField rePassword;
	private TextField<String> username;
	private TextField<String> email;
	// persoana
	private TextField<String> firstName;
	private TextField<String> lastName;
	private TextField<String> CNP;
	// student
	private TextField<Integer> an;
	private TextField<String> prenumeTata;
	private TextField<String> semian;
	private TextArea<String> grupa;
	private TextField<String> numarMatricol;
	private TipContComboBox tipContComboBox;
	// profesor
	private TextField<String> homePage;
	private TextField<String> office;
	private TextField<String> department;
	private TextArea<String> about;
	private TextField<String> titluUniversitar;
	// absolvent
	private TextField<Integer> anAbsolvire;

	private final ValueMap properties = new ValueMap();

	private final class UserDetailsStep extends WizardStep {
		private static final long serialVersionUID = 1L;

		public UserDetailsStep() {
			setTitleModel(new ResourceModel("userdetails.title"));
			setSummaryModel(new StringResourceModel("userdetails.summary", this, new Model<Person>(person)));

			final WebMarkupContainer dateStudent;
			final WebMarkupContainer dateProfesor;
			final WebMarkupContainer dateAbsolvent;

			dateStudent = new WebMarkupContainer("dateStudent");
			dateStudent.setOutputMarkupPlaceholderTag(true);
			dateProfesor = new WebMarkupContainer("dateProfesor");
			dateProfesor.setOutputMarkupPlaceholderTag(true);
			dateAbsolvent = new WebMarkupContainer("dateAbsolvent");
			dateAbsolvent.setOutputMarkupPlaceholderTag(true);

			add(dateStudent);
			add(dateProfesor);
			add(dateAbsolvent);

			// detali profesor
			dateProfesor.add(titluUniversitar = new TextField<String>("titluUniversitar", new PropertyModel<String>(
					person.getProfesor(), "titluUniversitar")));
			dateProfesor.add(homePage = new TextField<String>("homePage", new PropertyModel<String>(person
					.getProfesor(), "homePage")));
			dateProfesor.add(office = new TextField<String>("office", new PropertyModel<String>(person.getProfesor(),
					"office")));
			dateProfesor.add(department = new TextField<String>("departament", new PropertyModel<String>(person
					.getProfesor(), "departament")));
			dateProfesor.add(about = new TextArea<String>("about", new PropertyModel<String>(person.getProfesor(),
					"about")));
			homePage.add(new AbstractValidator<String>() {

				private static final long serialVersionUID = 1L;

				@Override
				protected void onValidate(IValidatable<String> validatable) {
					String value = validatable.getValue();
					if (value.length() != 0) {
						if (!value.startsWith("http://"))
							error(validatable, "error.proiecte.bibliografie.link");
						if (value.length() <= 12)
							error(validatable, "error.proiecte.bibliografie.link.scurt");
					}
				}
			});

			titluUniversitar.setRequired(true);
			homePage.setRequired(false);
			office.setRequired(false);
			department.setRequired(false);
			about.setRequired(false);

			homePage.setType(String.class);
			office.setType(String.class);
			department.setType(String.class);
			about.setType(String.class);
			titluUniversitar.setType(String.class);
			// ////////////////////////////////////////
			// detali student
			dateStudent.add(numarMatricol = new TextField<String>("numarMatricol", new PropertyModel<String>(person
					.getStudent(), "numarMatricol")));
			dateStudent.add(an = new TextField<Integer>("an", new PropertyModel<Integer>(person.getStudent(), "an")));
			dateStudent.add(prenumeTata = new TextField<String>("prenumeTata", new PropertyModel<String>(person
					.getStudent(), "prenumeTata")));
			dateStudent.add(semian = new TextField<String>("semian", new PropertyModel<String>(person.getStudent(),
					"semian")));
			dateStudent.add(grupa = new TextArea<String>("grupa", new PropertyModel<String>(person.getStudent(),
					"grupa")));

			numarMatricol.setRequired(true);
			an.setRequired(false);
			prenumeTata.setRequired(false);
			semian.setRequired(false);
			grupa.setRequired(false);

			an.setType(Integer.class);
			prenumeTata.setType(String.class);
			semian.setType(String.class);
			grupa.setType(String.class);
			numarMatricol.setType(String.class);

			// /detalii absolvent
			dateAbsolvent.add(anAbsolvire = new TextField<Integer>("anAbsolvire", new PropertyModel<Integer>(person
					.getAbsolvent(), "anAbsolvire")));

			anAbsolvire.setRequired(true);

			anAbsolvire.setType(Integer.class);

			// ////////////////////////////////////////
			// / detalii persoana
			add(firstName = new TextField<String>("first-name", new PropertyModel<String>(person, "prenume")));
			add(lastName = new TextField<String>("last-name", new PropertyModel<String>(person, "nume")));
			add(CNP = new TextField<String>("cnp", new PropertyModel<String>(person, "CNP")));
			CNP.add(new AbstractValidator<String>() {

				/**
				 * 
				 */
				private static final long serialVersionUID = 1L;

				@Override
				protected void onValidate(IValidatable<String> validatable) {
					String input = validatable.getValue();
					if (input.length() == 0)
						return;

					String expression = "\\d{13}";
					CharSequence inputStr = input;
					Pattern pattern = Pattern.compile(expression);
					Matcher matcher = pattern.matcher(inputStr);
					if (!(matcher.matches()))
						error(validatable, "error.cnp.not.valid");
					// TODO mai trebuie facute validari pentru cnp. vezi
					// TODO http://www.validari.ro/cnp

				}
			});

			firstName.setRequired(true);
			lastName.setRequired(true);
			CNP.setRequired(false);

			firstName.setType(String.class);
			lastName.setType(String.class);
			CNP.setType(String.class);

			// ///////////////////////////////////////

			add(tipContComboBox = new TipContComboBox("tipCont", Arrays.asList(TipContEnum.values())));

			tipContComboBox.setOutputMarkupId(true);
			tipContComboBox.setModel(new Model<TipContEnum>(TipContEnum.STUDENT));
			tipContComboBox.add(new AjaxFormComponentUpdatingBehavior("onchange") {

				private static final long serialVersionUID = 1L;

				@Override
				protected void onUpdate(AjaxRequestTarget target) {
					dateStudent.setVisible(tipContComboBox.getModelObject().equals(TipContEnum.STUDENT));
					dateProfesor.setVisible(tipContComboBox.getModelObject().equals(TipContEnum.PROFESSOR));
					dateAbsolvent.setVisible(tipContComboBox.getModelObject().equals(TipContEnum.ABSOLVENT));

					target.addComponent(dateStudent);
					target.addComponent(dateProfesor);
					target.addComponent(dateAbsolvent);
				}
			});

			dateStudent.setVisible(tipContComboBox.getModelObject().equals(TipContEnum.STUDENT));
			dateProfesor.setVisible(tipContComboBox.getModelObject().equals(TipContEnum.PROFESSOR));
			dateAbsolvent.setVisible(tipContComboBox.getModelObject().equals(TipContEnum.ABSOLVENT));
		}
	}

	/**
	 * 
	 * @author Marius Dumitriu - (Jun 3, 2010 - 11:40:54 PM)
	 * 
	 */
	private final class UserNameStep extends WizardStep {

		private static final long serialVersionUID = 1L;

		public UserNameStep() {
			super(new ResourceModel("form.title"), new ResourceModel("form.subtitle"));

			add(username = new TextField<String>("username", new PropertyModel<String>(person.getUser(), "login")));
			add(password = new PasswordTextField("password", new PropertyModel<String>(person.getUser(), "password")));
			add(rePassword = new PasswordTextField("re-password", new PropertyModel<String>(properties, "re-password")));
			add(email = new TextField<String>("email", new PropertyModel<String>(person.getUser(), "email")));

			username.setRequired(true);
			email.setRequired(true);

			username.setType(String.class);
			password.setType(String.class);
			rePassword.setType(String.class);
			email.setType(String.class);

			email.add(EmailAddressValidator.getInstance());
			rePassword.add(new AbstractValidator<String>() {

				private static final long serialVersionUID = 1L;

				@Override
				protected void onValidate(IValidatable<String> validatable) {
					if (!validatable.getValue().equals(password.getInput()))
						error(validatable, "error.password.dont.match");
				}
			});
			username.add(new AbstractValidator<String>() {

				/**
				 * 
				 */
				private static final long serialVersionUID = 1L;

				@Override
				protected void onValidate(IValidatable<String> validatable) {
					if (userService.findUserByLogin(validatable.getValue()) != null)
						error(validatable, "error.login.existent");

				}
			});

		}

	}

	protected Component newButtonBar(String id) {
		return new MyWizardButtonBar(id, this, getForm()) {

			private static final long serialVersionUID = 1L;

			public void onFinishClick(AjaxRequestTarget target) {
				try {
					onFinish(target);

					Page page = NewUserWizardPanels.this.getPage();
					page.get("content").replaceWith(backComponent);
					target.addComponent(page.get("content"));
					page.get(BasePage.ERRORS_PANEL).setVisible(true);
					target.addComponent(page.get(BasePage.ERRORS_PANEL));
					info(page.getString("operation.success"));
					info(page.getString("register.success"));

				} catch (ServiceException e) {

					error(e.getMessage());
				}

			}

			public void onCancelClick(AjaxRequestTarget target) {

				Page page = this.getPage();

				page.get("content").replaceWith(backComponent);

				target.addComponent(page.get("content"));
				page.get(BasePage.ERRORS_PANEL).setVisible(true);
				target.addComponent(page.get(BasePage.ERRORS_PANEL));
				warn(page.getString("operation.canceled"));
			}

		};
	}

	public NewUserWizardPanels(String id, Component back) {
		// pun pe false ca sa nu incarce css-ul default de la wicket.
		super(id, false);

		person = new Person();

		person.setAbsolvent(new Absolvent());
		person.setProfesor(new Profesor());
		person.setStudent(new Student());
		person.setUser(new User());

		setDefaultModel(new CompoundPropertyModel<NewUserWizardPanels>(this));
		WizardModel model = new WizardModel();
		model.add(new UserNameStep());
		model.add(new UserDetailsStep());

		init(model);
		this.backComponent = back;
		setOutputMarkupId(true);

	}

	@Override
	public void onFinish(AjaxRequestTarget target) throws ServiceException {
		switch (tipContComboBox.getModelObject()) {
		case ABSOLVENT:
			person.setProfesor(null);
			person.setStudent(null);
			userService.registerAbsolventUser(person);
			break;
		case PROFESSOR:
			person.setAbsolvent(null);
			person.setStudent(null);
			userService.registerProfesorUser(person);
			break;
		case STUDENT:
			person.setProfesor(null);
			person.setAbsolvent(null);
			userService.registerStudentUser(person);
			break;
		}

	}
}
